﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Microsoft.HomeServer.Extensibility;
using Microsoft.HomeServer.SDK.Interop.v1;
using RouterControl.Whs.SingletonService;

namespace RouterControl.WhsAddIn
{
    [TabIdentifier(RouterControlConsoleTab2.TabId)]
	public partial class RouterControlConsoleTab2 : UserControl, IConsoleTab
	{
        public const string TabId = "RouterControlConsoleTab";

        public enum RouterState
        {
            Undefined,
            ServiceNotRunning,
            NoRouterSelected,
            ConnectingRouter,
            RouterPresent,
            RouterMissing,
            UpdateAvailable
        }

        private readonly log4net.ILog _log = Logging.LogFactory.Instance.GetLog<RouterControlConsoleTab2>();
		private IConsoleServices _services;
		private WHSInfoClass _whsInfo;
        private SingletonService2Factory _singletonService = new SingletonService2Factory();
		private RouterState _state = RouterState.Undefined;
        private bool _lastDeviceLostState = false;

		public IConsoleServices Services
		{
			get { return _services; }
		}

        static RouterControlConsoleTab2()
        {
            // make sure the xceed chart license is set
            Xceed.Chart.Licenser.LicenseKey = Microsoft.HomeServer.Controls.CommonSettings.XceedLicenseKey;
        }

		public RouterControlConsoleTab2(int width, int height, IConsoleServices consoleServices)
		{
			// init
			InitializeComponent();

			// hook
			this.Size = new Size(width, height);
			_services = consoleServices;
			_whsInfo = new WHSInfoClass();
			_whsInfo.Init(Whs.Properties.Constants.ApplicationName);
		}

		public bool GetHelp()
		{
			return false;
		}

		public Guid SettingsGuid
		{
			get { return RouterControlSettingsTab2.SettingsTabGuid; }
		}

		public Control TabControl
		{
			get { return this; }
		}

		public Bitmap TabImage
		{
			get { return Properties.Resources.imgTabLogo; }
		}

		public string TabText
		{
			get { return Properties.Resources.txtRouterControlConsoleTabTitle; }
		}

		private void checkUpdateAvailableTimer_Tick(object sender, EventArgs e)
		{
			try
			{
				if (_singletonService.IsWindowsServiceRunning() != SingletonService2Factory.ServiceStatus.Running)
					return;

				// update status
				var newVersion = _singletonService.Channel.GetNewerVersion();

                if (newVersion == null)
					this.updateAvailableButton.Visible = false;
				else
				{
					this.updateAvailableButton.ToolTipText = string.Format(
						Properties.Resources.txtUpdateAvailableButtonTooltip,
						newVersion.Value.VersionStr
						);
	
					this.updateAvailableButton.Visible = true;

                    // change to update mode?
                    if (Properties.Settings.Default.IgnoreUpdateReleaseId != newVersion.Value.ReleaseId)
                    {
                        SetState(RouterState.UpdateAvailable);
                    }
				}
			}
			catch (Exception ex)
			{
				_log.Error("Failed to update update status", ex);
			}
		}

		public void SetState(RouterState state)
		{
			// no change?
			if (_state == state)
				return;

			// log
			if (_log.IsDebugEnabled)
				_log.Debug("Changing state start: " + _state + " to " + state);

			// no router stuff
			try
			{
				this.SuspendLayout();

				this.selectRouterBtn.Visible = false;
				this.changeRouterBtn.Visible = false;

                // cleanup
                foreach (ConsoleControls.ConsoleControlBase c in this.flowLayoutPanel.Controls)
                {
                    try
                    {
                        c.Dispose();
                    }
                    catch (Exception ex)
                    {
                        _log.Warn("Failed to dispose control", ex);
                    }
                }

                this.flowLayoutPanel.Controls.Clear();

                // change state
				switch (state)
				{
					case RouterState.ServiceNotRunning:
						this.flowLayoutPanel.Controls.Add(new ConsoleControls.RouterServiceNotRunning(this));
						break;

                    case RouterState.UpdateAvailable:
                        this.flowLayoutPanel.Controls.Add(new ConsoleControls.UpdateAvailable(this));
                        break;

                    case RouterState.NoRouterSelected:
						this.flowLayoutPanel.Controls.Add(new ConsoleControls.NoRouterSelected(this));

						this.selectRouterBtn.Visible = true;
						break;

                    case RouterState.RouterMissing:
                        this.flowLayoutPanel.Controls.Add(new ConsoleControls.RouterMissing(this));

                        this.changeRouterBtn.Visible = true;
                        break;

                    case RouterState.ConnectingRouter:
                        this.flowLayoutPanel.Controls.Add(new ConsoleControls.ConnectingRouter(this));
                        break;

                    case RouterState.RouterPresent:
                        this.flowLayoutPanel.Controls.Add(new ConsoleControls.RouterOverview(this));
                        this.flowLayoutPanel.Controls.Add(new ConsoleControls.OnlineStatus(this));

                        if (_singletonService.Channel.IsTrafficStatsEnabled())
                            this.flowLayoutPanel.Controls.Add(new ConsoleControls.TrafficGraph(this));

                        if ((_singletonService.Channel.IsPortForwardingsMonitoringEnabled() & ExtendedEnabled.Enabled) == ExtendedEnabled.Enabled)
                            this.flowLayoutPanel.Controls.Add(new ConsoleControls.PortForwarding(this));

                        this.changeRouterBtn.Visible = true;
                        break;

                    default:
                        _log.Warn("Unknown state: " + state);
                        break;
                }

				this.ResumeLayout();

				// finalize
				_state = state;

				// log
				if (_log.IsDebugEnabled)
					_log.Debug("Changing state done: " + state);
			}
			catch (Exception ex)
			{
				_log.Fatal("Failed to change state from " + _state + " to " + state, ex);

				throw;
			}
		}

        public void ResetState()
        {
            try
            {
                if (_singletonService.IsWindowsServiceRunning() != SingletonService2Factory.ServiceStatus.Running)
                    SetState(RouterState.ServiceNotRunning);

                else
                {
                    var newVersion = _singletonService.Channel.GetNewerVersion();

                    if ((newVersion != null) && 
                        (newVersion.Value.ReleaseId != Properties.Settings.Default.IgnoreUpdateReleaseId))
                        SetState(RouterState.UpdateAvailable);

                    else if (_singletonService.Channel.IsSelectedDeviceLost())
                        SetState(RouterState.RouterMissing);

                    else if (_singletonService.Channel.IsDeviceSelected())
                        SetState(RouterState.ConnectingRouter);

                    else
                        SetState(RouterState.NoRouterSelected);
                }

            }
            catch (Exception x)
            {
                _log.Fatal("Failed to reset state", x);

                throw;
            }
        }

		private void RouterControlConsoleTab2_Load(object sender, EventArgs e)
		{
			if (_log.IsDebugEnabled)
				_log.Debug("Loading start");

			try
			{
                ResetState();

				// done
				if (_log.IsDebugEnabled)
					_log.Debug("Loading done");
			}
			catch (Exception ex)
			{
				_log.Fatal("Loading failed", ex);

				throw;
			}
		}

		public void OpenRouterControlSettings()
		{
			try
			{
				_services.OpenSettings(RouterControlSettingsTab2.SettingsTabGuid);
			}
			catch (Exception x)
			{
				_log.Error("Failed to open settings", x);

				Microsoft.HomeServer.Controls.QMessageBox.Show(
					x.Message,
					Properties.Resources.txtOpenSettingsFailedTitle,
					MessageBoxButtons.OK,
					MessageBoxIcon.Error
					);
			}
		}

		private void changeRouterBtn_Click(object sender, EventArgs e)
		{
			OpenRouterControlSettings();
		}

		private void selectRouterBtn_Click(object sender, EventArgs e)
		{
			OpenRouterControlSettings();
		}

		private void updateAvailableButton_Click(object sender, EventArgs e)
		{
            SetState(RouterState.UpdateAvailable);
		}

        private void checkDeviceLostTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                // ensure the singleton service is running
                if (_singletonService.IsWindowsServiceRunning() != SingletonService2Factory.ServiceStatus.Running)
                {
                    ResetState();

                    return;
                }

                // only if a router is present or missing
	            if ((_state != RouterState.RouterPresent) && (_state != RouterState.RouterMissing))
	                return;
	
	            // if a device is selected but not found...
	            var isLost = _singletonService.Channel.IsSelectedDeviceLost();
	
	            if (isLost != _lastDeviceLostState)
	            {
                    if (isLost)
                    {
                        _log.Info("Recognized device lost; resetting state...");

                        ResetState();
                    }
                    else
                    {
                        _log.Info("Recognized device restore; resetting state...");

                        ResetState();
                    }
	
	                _lastDeviceLostState = isLost;
	            }
            }
            catch (Exception ex)
            {
                _log.Error("Failed to check and handle device lost", ex);

                // do not forward
            }
        }

	}
}
